#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTimer>
#include <QXmlSimpleReader>
#include <QXmlInputSource>

#include "Server.h"
#include "ServerChecker.h"
#include "XmlStatsHandler.h"

#ifdef Q_OS_WIN32
#include "WindowsPing.h"
#endif

ServerChecker::ServerChecker( int checkInterval, QObject *parent ) :
    QObject(parent),
    mCheckInterval( checkInterval ),
    mCurrentServerInCheck( -1 ),
    mNetworkManager( new QNetworkAccessManager(this) ),
    mServers( NULL ),
    mTimer( new QTimer(this) )
{
#ifdef Q_OS_WIN32
    mPing = new WindowsPing( this );
#else
    qFatal( "ServerChecker: Unsupported os." );
#endif

    // Timer.
    int intervalInMilliseconds = mCheckInterval * 60 * 1000;
    mTimer->setInterval( intervalInMilliseconds );
    mTimer->setSingleShot( true );

    connect( mNetworkManager, SIGNAL(finished(QNetworkReply*)),
             this, SLOT(replyFinished(QNetworkReply*)) );
    connect( mPing, SIGNAL(hostUnavailable()),
             this, SLOT(hostUnavailable()) );
    connect( mPing, SIGNAL(pingResult(int)),
             this, SLOT(pingResult(int)) );
}

void ServerChecker::finishCheck()
{
    mTimer->start();
}

void ServerChecker::hostUnavailable()
{
    Server *server = mServers->at( mCurrentServerInCheck );
    server->setPing( Server::HOST_UNAVAILABLE );

    pingNextServer();
}

void ServerChecker::networkError( QNetworkReply::NetworkError code )
{
    QNetworkReply *reply = dynamic_cast<QNetworkReply *>( sender() );
    qDebug() << "Network error:" << reply->errorString();

    pingNextServer();
}

void ServerChecker::replyFinished( QNetworkReply *reply )
{
    QString replyText = reply->readAll();
    reply->deleteLater();

    qDebug() << "Stats:" << replyText;

    QXmlSimpleReader xmlReader;
    QXmlInputSource source;
    source.setData( replyText );

    Server *server = mServers->at( mCurrentServerInCheck );

    XmlStatsHandler handler( server );
    xmlReader.setContentHandler( &handler );
    xmlReader.setErrorHandler( &handler );

    xmlReader.parse( source );

    pingNextServer();
}

void ServerChecker::pingNextServer()
{
    mCurrentServerInCheck += 1;
    if ( mCurrentServerInCheck >= mServers->size() )
    {
        finishCheck();
        return;
    }

    Server *server = mServers->at( mCurrentServerInCheck );
    mPing->send( server->url() );
}

void ServerChecker::pingResult( int delay )
{
    Server *server = mServers->at( mCurrentServerInCheck );
    server->setPing( delay );

    if ( server->checkStats() )
    {
        qDebug() << "Reading stats.";
        mNetworkManager->get( QNetworkRequest(server->url()) );
    }
    else
    {
        pingNextServer();
    }
}

void ServerChecker::setServers( ServerList *servers )
{
    mServers = servers;
}

void ServerChecker::startCheck()
{
    mCurrentServerInCheck = -1;
    pingNextServer();
}

void ServerChecker::start()
{
    if ( mServers == NULL )
    {
        return;
    }

    // Stop timer cause this function can be called more than ones.
    mTimer->stop();
    startCheck();
}
